﻿using System;
using System.Collections.Generic;
using System.Text;

namespace GA
{
    /// <summary>
    /// Genetic algorithms chromosome class
    /// </summary>
    /// <remarks>Written by Kerem KAT, keremkat, gmail, com</remarks>
    public class Chromosome
    {
        private Random x = new Random();
        public List<int> genes;
        public int Fitness = int.MaxValue;

        public int N;

        public decimal DecimalRandom()
        {
            return (decimal)(x.NextDouble() * (double)(decimal.MaxValue - 1));
        }

        public decimal DecimalRandom(decimal max)
        {
            return (decimal)(x.NextDouble() * (double)((decimal.MaxValue - 1) / max));
        }

        public Chromosome(int n)
        {
            N = n;
            genes = new List<int>(N);
            int[] p = Combinatorics.Permutation(N, DecimalRandom(Combinatorics.fact(N)));
            for (int i = 0; i < N; ++i)
                genes.Add(p[i]);
            UpdateFitness();
        }

        public Chromosome(int seed, int n)
        {
            N = n;
            Random x = new Random(seed);
            genes = new List<int>(N);
            int[] p = Combinatorics.Permutation(N, DecimalRandom(Combinatorics.fact(N)));
            for (int i = 0; i < N; ++i)
                genes.Add(p[i]);
            UpdateFitness();
        }

        public Chromosome(List<int> genList)
        {
            genes = new List<int>(genList.Count);
            foreach (int x in genList)
                genes.Add(x);
            N = genList.Count;
            UpdateFitness();
        }

        public Chromosome Copy()
        {
            return new Chromosome(genes);
        }

        public static Chromosome CrossOver(Chromosome c, Chromosome c2)
        {
            if (c == c2)
                return c;
            Random x = new Random();
            Chromosome ret = new Chromosome(c.N);
            Chromosome cc = c.Copy();
            Chromosome cc2 = c2.Copy();

            ret.genes.Clear();
            for (int i = 0; i < ret.N; ++i)
            {
                if (x.Next() % 2 == 1)
                {
                    ret.genes.Add(cc2.genes[0]);
                    cc.genes.Remove(cc2.genes[0]);
                    cc2.genes.Remove(cc2.genes[0]);
                }
                else
                {
                    ret.genes.Add(cc.genes[0]);
                    cc2.genes.Remove(cc.genes[0]);
                    cc.genes.Remove(cc.genes[0]);
                }
            }
            ret.UpdateFitness();
            return ret;
        }

        public void Mutate()
        {
            int r1 = x.Next(N);
            int r2 = x.Next(N);
            int t;
            t = genes[r1];
            genes[r1] = genes[r2];
            genes[r2] = t;
            UpdateFitness();
        }

        private int fitness()
        {
            int crissCount = 0;
            int n = genes.Count;
            int j1 = 0, j2 = 0;

            foreach (int i1 in genes)
            {
                j2 = 0;
                foreach (int i2 in genes)
                {
                    if (i1 == i2 && j1 == j2)
                    {
                        j2++;
                        continue;
                    }

                    if (i1 == i2)
                        crissCount++;
                    if (j1 == j2)
                        crissCount++;
                    if (i2 - i1 == j2 - j1 || i2 - i1 == j1 - j2)
                        crissCount++;
                    j2++;
                }
                j1++;
            }
            return crissCount;
        }

        public void UpdateFitness()
        {
            Fitness = fitness();
        }

        public override string ToString()
        {
            string ret = "";
            foreach (int i in genes)
                ret += i.ToString() + " ";
            return ret.TrimEnd();
        }

    }
}
